%{
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include <ctype.h>
#include <sys/types.h>
#include <dirent.h>
#include <sys/stat.h>
#include "admin.h"

extern "C" {

void yyerror(const char *s, ...);
extern int yylex(void);
int yywrap();
}
extern FILE *yyin;
void scanf_dir(char *path);
Util util;
std::string gstr;
TypeStat typestat;
%}

%token COMMENTS WELL_NUMBER INCLUDE STRING LAB RAB 
%token HEADERFILE UNDEF WORD DEFINE
%token NUMBER RPT LPT HEXNUMBER MUL EQ
%token OR AND ASSIGN NEQ ADD SUB DIV PER
%token SIZEOF LBB RBB
%token CHAR SHORT INT LONG SIGNED UNSIGNED
%token IF ELSE ELIF ENDIF

%left OR
%left AND
%left EQ
%left NEQ
%left ADD SUB
%left MUL DIV PER
%nonassoc FORCE_TYPE

%%
statements:statement {
	$$ = $1;
	gstr = $$;
}
| statements statement {
	$$ = $1 + $2;
	gstr = $$;
}

statement:comment
| include
| undef
| define
| well_number_if_statement {
	printf("%s\n", $$.c_str());
}
;

comment: COMMENTS {
	$$ = "\n" + $1 + "\n";
}

include: WELL_NUMBER INCLUDE STRING {
	$$ = $1 + $2 + " " + $3 + "\n";
}
| WELL_NUMBER INCLUDE LAB HEADERFILE RAB {
	$$ = $1 + $2 + " " + $3 + $4 + $5 + "\n";
}

undef: WELL_NUMBER UNDEF WORD {
	$$ = $1 + $2 + "\t" + $3 + "\n";
}

define:WELL_NUMBER DEFINE WORD {
	$$ = $1 + $2 + "\t" + $3 + "\n";
}
| WELL_NUMBER DEFINE WORD expr{
	$$ = $1 + $2 + "\t" + $3 + "\t" + $4 + "\n";
}

expr: STRING
| number
| sizeof

type:type_only
| SIGNED type_only
| UNSIGNED type_only

type_only:CHAR
| SHORT
| INT
| LONG

number:NUMBER
| HEXNUMBER
| number MUL NUMBER {
	$$ = $1 + $2 + $3 + "\n";
}
| number MUL HEXNUMBER {
	$$ = $1 + $2 + $3 + "\n";
}
| LPT number RPT{
	$$ = $1 + $2 + $3 + "\n";
}
| LPT WORD number RPT {
	$$ = $1 + $2 + $3 + $4 + "\n";
}

sizeof: sizeofvalue

sizeofvalue: SIZEOF var_word {
	$$ = $1 + $2 + "\n";
}
| sizeofvalue DIV sizeofvalue {
	$$ = $1 + $2 + $3 + "\n";
}
| LPT sizeofvalue RPT {
	$$ = $1 + $2 + $3 + "\n";
}
| force_type  sizeofvalue %prec FORCE_TYPE{
	$$ = $1 + $2 + "\n";
}

force_type: LPT type RPT {
	$$ = $1 + $2 + $3 + "\n";
}

var_word:WORD
| LPT var_word RPT {
	$$ = $1 + $2 + $3 + "\n";
}
| var_word LBB number RBB {
	$$ = $1 + $2 + $3 + $4 + "\n";
}

 /*#if 1 xxxx endif*/
well_num_else:WELL_NUMBER ELSE {
	$$ = $1 + $2;
}

well_num_endif:WELL_NUMBER ENDIF {
	$$ = $1 + $2;
}
well_number_expr:number
| WORD

wellnumber_if_block:WELL_NUMBER IF well_number_expr  {
	$$ = $1 + $2 + " " + $3 + " ";
}

wellnumber_elif_block:WELL_NUMBER ELIF well_number_expr {
	$$ = $1 + $2 + " " + $3 + " ";
}

wellnumber_elif_recursion:statements wellnumber_elif_block {
	$$ = $1 + $2;
}
| wellnumber_elif_recursion statements wellnumber_elif_block {
	$$ = $1 + $2 + $3;
}

well_number_if_statement:wellnumber_if_block statements well_num_endif {
	$$ = $1 + $2 + $3 + "\n";
}
| wellnumber_if_block statements well_num_else statements well_num_endif {
	$$ = $1 + $2 + $3 + $4 + $5 + "\n";
}
|wellnumber_if_block wellnumber_elif_recursion statements well_num_else statements well_num_endif{
	$$ = $1 + $2 + $3 + $4 + $5 + $6 + "\n";
}
 


%%
void yyerror(const char *s, ...)
{
	//return;
    //va_list ap;
    //va_start(ap, s);
    //vfprintf(stderr, s, ap);
    //fprintf(stderr, "\n");

    if (gstr.length() > 0) {
    	//fprintf(stderr, "%s\n", gstr.c_str());
    	gstr = "";
    }
    //exit(-1);
}

int main(int argc, char **argv)
{
	char *dir = argv[1];
#ifdef YYDEBUG
	yydebug = 0;	
#endif	
	scanf_dir(dir);
}

int yywrap()
{
	return 1;
}

void type_init()
{
	typestat.Reset();
	typestat.AddTypeItem("char", CHAR);
	typestat.AddTypeItem("short", SHORT);
	typestat.AddTypeItem("int", INT);
	typestat.AddTypeItem("long", LONG);
	typestat.AddTypeItem("signed", SIGNED);
	typestat.AddTypeItem("unsigned", UNSIGNED);
}

void scan_file(char *filename)
{
	char filetmp[1024] = {0};
	FILE *fp_in = NULL;
	FILE *fp_out = NULL;

	
	sprintf(filetmp, "%s_back", filename);
	fp_in = fopen(filename, "r");
	fp_out = fopen(filetmp, "w");
	if (!fp_in || !fp_out) {
		printf("fopen failed %s \n%s\n", filename, filetmp);
		goto end;
	}

	yyin = fp_in;
	type_init();
	do {
		yyparse();
	}while(!feof(yyin));

	//printf("%s\n", gstr.c_str());

end:
	if (fp_in) {
		fclose(fp_in);
	}
	if (fp_out) {
		fclose(fp_out);
	}
}

void scanf_dir(char *path)
{
	DIR *d = NULL;
    struct dirent *dp = NULL; 
    struct stat st;   
    char p[1024] = {0};
    int len;

    if(stat(path, &st) < 0 || !S_ISDIR(st.st_mode)) {
        printf("invalid path: %s\n", path);
        return;
    }
    if(!(d = opendir(path))) {
        printf("opendir[%s] error: %m\n", path);
        return;
    }
    while((dp = readdir(d)) != NULL) {
        if((!strncmp(dp->d_name, ".", 1)) || (!strncmp(dp->d_name, "..", 2))) {
            continue;
        }
        snprintf(p, sizeof(p) - 1, "%s/%s", path, dp->d_name);
        stat(p, &st);
        if(!S_ISDIR(st.st_mode)) {
        	//过滤下c文件
			len = strlen(p);
			if (p[len-1] != 'c' || p[len-2] != '.') {
				continue;
			}
            printf("%s\n", dp->d_name);
            scan_file(p);
        } else {
            printf("******%s/\n", dp->d_name);
            scanf_dir(p);
        }
    }
    closedir(d);
}